/*
 * GuiFrame.java
 *
 * Created on Oct 6, 2010, 2:25:33 AM
 */
package raytracing.gui;

import java.awt.Cursor;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;

import javax.swing.SwingWorker;
import javax.vecmath.Vector3d;

import model.Scene;
import raytracing.RayTracer;
import raytracing.TraceDepth;
import scparser.factory.primitiveFactory.FactoryException;
import camera.PinHoleCamera;
import camera.ThinlensCamera;


/**
 *
 * @author xin
 */
public class GuiFrame extends javax.swing.JFrame implements Runnable, PropertyChangeListener {

    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private Scene scene;
	private boolean show;
	private boolean time;
	private boolean progress;

	private RayTracer rayTracer;

	// Variables declaration - do not modify//GEN-BEGIN:variables
	private javax.swing.ButtonGroup buttonGroup1;
	private CameraJPanel cameraJPanel2;
	private ImageJPanel imageJPanel1;
	private javax.swing.JButton jButton1;
	private javax.swing.JButton jButton2;
	private javax.swing.JLabel jLabel1;
	private javax.swing.JProgressBar jProgressBar1;
	private OptionsJPanel optionsJPanel1;
	// End of variables declaration//GEN-END:variables

	
	/** Creates new form GuiFrame */
    public GuiFrame() {
        initComponents();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */

    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        setButtonGroup(new javax.swing.ButtonGroup());
        jLabel1 = new javax.swing.JLabel();
        jProgressBar1 = new javax.swing.JProgressBar();
        jProgressBar1.setStringPainted(true);
        
        jButton1 = new javax.swing.JButton();
        jButton1.setEnabled(false);
        optionsJPanel1 = new OptionsJPanel();
        
        
        optionsJPanel1.jButtonOutput.addActionListener(new java.awt.event.ActionListener() {
            @SuppressWarnings("static-access")
			public void actionPerformed(java.awt.event.ActionEvent evt) {
            	int retVal;
            	retVal = optionsJPanel1.jFileChooserOutput.showSaveDialog(optionsJPanel1);
                if (retVal == optionsJPanel1.jFileChooserOutput.APPROVE_OPTION) {
                	saveFileActionPerformed(evt);
					
				}
            }

			private void saveFileActionPerformed(ActionEvent evt) {
				File file = optionsJPanel1.jFileChooserOutput.getSelectedFile();				
				String extension;
				if (file != null) {
					extension = file.getAbsolutePath().substring(file.getAbsolutePath().length()-3);
					if ("bmp".equalsIgnoreCase(extension)) {
						RayTracer.saveBMP(rayTracer.getBuf(), file.getAbsolutePath());
					} else if ("png".equalsIgnoreCase(extension)) {
						RayTracer.savePNG(rayTracer.getBuf(), file.getAbsolutePath());
					} else {
						new AlertJFrame("extension picture error, choose between bmp or png.");
					}
				}
				
			}
        });
        
        jButton2 = new javax.swing.JButton();
        cameraJPanel2 = new CameraJPanel();
        imageJPanel1 = new ImageJPanel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jLabel1.setText("Ray Tracing");

        jButton1.setText("Render");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                renderActionPerformed(evt);
            }
        });

        jButton2.setText("Build Scene");
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buildActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                    .addComponent(jLabel1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 471, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jProgressBar1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                            .addComponent(cameraJPanel2, 0, 0, Short.MAX_VALUE)
                            .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                                .addComponent(optionsJPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(imageJPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                            .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 142, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(jButton2, javax.swing.GroupLayout.PREFERRED_SIZE, 142, javax.swing.GroupLayout.PREFERRED_SIZE))))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(jLabel1)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addComponent(imageJPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(optionsJPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 12, Short.MAX_VALUE)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(147, 147, 147)
                        .addComponent(jButton2, javax.swing.GroupLayout.PREFERRED_SIZE, 40, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 40, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(layout.createSequentialGroup()
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(cameraJPanel2, 0, 0, Short.MAX_VALUE)))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jProgressBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 38, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void renderActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
    	scene.bucket = Integer.parseInt(imageJPanel1.bucket.getText());
    	scene.image.height = Integer.parseInt(imageJPanel1.height.getText());
    	scene.image.width = Integer.parseInt(imageJPanel1.width.getText());
    	scene.image.aa.firstValue = Integer.parseInt(imageJPanel1.xAA.getText());
    	scene.image.aa.secondValue = Integer.parseInt(imageJPanel1.yAA.getText());
    	
    	Vector3d target = new Vector3d(Double.parseDouble(cameraJPanel2.xTarget.getText()),
    			Double.parseDouble(cameraJPanel2.yTarget.getText()),
    			Double.parseDouble(cameraJPanel2.zTarget.getText()));
    	Vector3d eye = new Vector3d(Double.parseDouble(cameraJPanel2.xEye.getText()),
    			Double.parseDouble(cameraJPanel2.yEye.getText()),
    			Double.parseDouble(cameraJPanel2.zEye.getText()));;
    	Vector3d up = new Vector3d(Double.parseDouble(cameraJPanel2.xUp.getText()),
    			Double.parseDouble(cameraJPanel2.yUp.getText()),
    			Double.parseDouble(cameraJPanel2.zUp.getText()));;
    	double fov = Double.parseDouble(cameraJPanel2.fov.getText());
    	double aspectRatio = Double.parseDouble(cameraJPanel2.aspect.getText());
    	
    	if (cameraJPanel2.jRadioButtonPinhole.isSelected()) {
    		scene.camera = new PinHoleCamera(target, eye, up, fov, aspectRatio);
    	} else {
    		double fdist = Double.parseDouble(cameraJPanel2.fdist.getText());
    		double lensr = Double.parseDouble(cameraJPanel2.lensr.getText());
    		scene.camera = new ThinlensCamera(target, eye, up, fov, aspectRatio, fdist, lensr);
    	}
    	
    	rayTracer = new RayTracer(scene, scene.image.width, scene.image.height, new TraceDepth(1, 1, 4));
    	rayTracer.DOF = Double.parseDouble("".equals(optionsJPanel1.dof.getText()) ? "0.0": optionsJPanel1.dof.getText());
    	
    	show = optionsJPanel1.show.isSelected();
    	time = optionsJPanel1.time.isSelected();
    	progress = optionsJPanel1.progress.isSelected();
    	
    	Thread thread = new Thread(rayTracer);
    	
    	
    	if (progress) {
    		setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
    		Task task = new Task();
    		task.addPropertyChangeListener(this);
    		new Thread(task).start();
    		task.execute();
//    		addPropertyChangeListener(this);
    	}
    	
    	thread.start();
    }//GEN-LAST:event_jButton1ActionPerformed

    private void buildActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
    	File file;
    	
		if ((file = optionsJPanel1.jFileChooserInput.getSelectedFile()) != null) {
    		try {
				scene = scparser.Parser.instance().parse(file.getAbsolutePath());
				setSceneValues(scene);
				jButton1.setEnabled(true);
				jProgressBar1.setValue(0);
			} catch (FactoryException e) {
				new AlertJFrame(e.getMessage());
			}
    	}     	
    }//GEN-LAST:event_jButton2ActionPerformed

    private void setSceneValues(Scene scene) {
    	imageJPanel1.bucket.setText(Integer.toString(scene.bucket));
    	imageJPanel1.height.setText(Integer.toString(scene.image.height));
    	imageJPanel1.width.setText(Integer.toString(scene.image.width));
    	imageJPanel1.xAA.setText(Integer.toString(scene.image.aa.firstValue));
    	imageJPanel1.yAA.setText(Integer.toString(scene.image.aa.secondValue));
    	
    	cameraJPanel2.aspect.setText(Double.toString(scene.camera.aspectRatio));
    	
    	if (scene.camera instanceof ThinlensCamera) {
    		cameraJPanel2.jRadioButtonThinlens.setSelected(true);
    		cameraJPanel2.fdist.setText(Double.toString(((ThinlensCamera)(scene.camera)).fdist));
    		cameraJPanel2.lensr.setText(Double.toString(((ThinlensCamera)(scene.camera)).lensr));
    	} else {
    		cameraJPanel2.jRadioButtonPinhole.setSelected(true);
    	}
    	
    	cameraJPanel2.xEye.setText(Double.toString(scene.camera.eye.x));
    	cameraJPanel2.yEye.setText(Double.toString(scene.camera.eye.y));
    	cameraJPanel2.zEye.setText(Double.toString(scene.camera.eye.z));
    	
    	cameraJPanel2.xTarget.setText(Double.toString(scene.camera.forward.x));
    	cameraJPanel2.yTarget.setText(Double.toString(scene.camera.forward.y));
    	cameraJPanel2.zTarget.setText(Double.toString(scene.camera.forward.z));
    	cameraJPanel2.xUp.setText(Double.toString(scene.camera.up.x));
    	cameraJPanel2.yUp.setText(Double.toString(scene.camera.up.y));
    	cameraJPanel2.zUp.setText(Double.toString(scene.camera.up.z));
    	cameraJPanel2.fov.setText(Double.toString(scene.camera.fov));
	}

    public void setButtonGroup(javax.swing.ButtonGroup buttonGroup1) {
		this.buttonGroup1 = buttonGroup1;
	}

	public javax.swing.ButtonGroup getButtonGroup() {
		return buttonGroup1;
	}

	@Override
	public void run() {
		this.setVisible(true);
		
	}
	
	class Task extends SwingWorker<Void, Void> {
		private long start;
        /*
         * Main task. Executed in background thread.
         */
        @Override
        public Void doInBackground() {
        	start = System.currentTimeMillis();
        	int prograssTask = 0;
            //Initialize progress property.
            setProgress(0);
            while (prograssTask < 100) {
                //Sleep for up to one second.
//                try {
//                    Thread.sleep(1000);
//                } catch (InterruptedException ignore) {}
                prograssTask = rayTracer.getProgreso().intValue()+1;
                setProgress(Math.min(prograssTask, 100));
            }
            return null;
        }

        /*
         * Executed in event dispatching thread
         */
        @Override
        public void done() {
            Toolkit.getDefaultToolkit().beep();
//            startButton.setEnabled(true);
            setCursor(null); //turn off the wait cursor
            if (time) {
            	new AlertJFrame("time elapsed: " + (System.currentTimeMillis()-start) + " ms.");
            }
            
            if (show) {
            	new ShowJFrame(rayTracer);
            }
        }
    }
	
	public void propertyChange(PropertyChangeEvent evt) {
		if ("progress" == evt.getPropertyName()) {
			int progress = (Integer) evt.getNewValue();
			jProgressBar1.setValue(progress);
		} 
	}
}
